home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / elvis-17.lha / elvis-1.7 / modify.c < prev    next >
C/C++ Source or Header  |  1993-01-06  |  10KB  |  475 lines

  1. /* modify.c */
  2.  
  3. /* This file contains the low-level file modification functions:
  4.  *    delete(frommark, tomark)    - removes line or portions of lines
  5.  *    add(frommark, text)        - inserts new text
  6.  *    change(frommark, tomark, text)    - delete, then add
  7.  */
  8.  
  9. #include "config.h"
  10. #include "vi.h"
  11.  
  12. #ifdef DEBUG2
  13. # include <stdio.h>
  14. static FILE *dbg;
  15.  
  16. /*VARARGS1*/
  17. debout(msg, arg1, arg2, arg3, arg4, arg5)
  18.     char    *msg, *arg1, *arg2, *arg3, *arg4, *arg5;
  19. {
  20.     if (!dbg)
  21.     {
  22.         dbg = fopen("debug.out", "w");
  23.         if (!dbg)
  24.             return;
  25.         setbuf(dbg, (FILE *)0);
  26.     }
  27.     fprintf(dbg, msg, arg1, arg2, arg3, arg4, arg5);
  28. }
  29. #endif /* DEBUG2 */
  30.  
  31. /* delete a range of text from the file */
  32. void delete(frommark, tomark)
  33.     MARK        frommark;    /* first char to be deleted */
  34.     MARK        tomark;        /* AFTER last char to be deleted */
  35. {
  36.     int        i;        /* used to move thru logical blocks */
  37.     REG char    *scan;        /* used to scan thru text of the blk */
  38.     REG char    *cpy;        /* used when copying chars */
  39.     BLK        *blk;        /* a text block */
  40.     long        l;        /* a line number */
  41.     MARK        m;        /* a traveling version of frommark */
  42.  
  43. #ifdef DEBUG2
  44.     debout("delete(%ld.%d, %ld.%d)\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark));
  45. #endif
  46.  
  47.     /* if not deleting anything, quit now */
  48.     if (frommark == tomark)
  49.     {
  50.         return;
  51.     }
  52.  
  53.     /* This is a change */
  54.     changes++;
  55.     significant = TRUE;
  56.  
  57.     /* supply clues to the redraw module */
  58.     redrawrange(markline(frommark), markline(tomark), markline(frommark));
  59.  
  60.     /* adjust marks 'a through 'z and '' as needed */
  61.     l = markline(tomark);
  62.     for (i = 0; i < NMARKS; i++)
  63.     {
  64.         if (mark[i] < frommark)
  65.         {
  66.             continue;
  67.         }
  68.         else if (mark[i] < tomark)
  69.         {
  70.             mark[i] = MARK_UNSET;
  71.         }
  72.         else if (markline(mark[i]) == l)
  73.         {
  74.             if (markline(frommark) == l)
  75.             {
  76.                 mark[i] -= markidx(tomark) - markidx(frommark);
  77.             }
  78.             else
  79.             {
  80.                 mark[i] -= markidx(tomark);
  81.             }
  82.         }
  83.         else
  84.         {
  85.             mark[i] -= MARK_AT_LINE(l - markline(frommark));
  86.         }
  87.     }
  88.  
  89.     /* Reporting... */
  90.     if (markidx(frommark) == 0 && markidx(tomark) == 0)
  91.     {
  92.         rptlines = markline(tomark) - markline(frommark);
  93.         rptlabel = "deleted";
  94.     }
  95.  
  96.     /* find the block containing frommark */
  97.     l = markline(frommark);
  98.     for (i = 1; lnum[i] < l; i++)
  99.     {
  100.     }
  101.  
  102.     /* process each affected block... */
  103.     for (m = frommark;
  104.          m < tomark && lnum[i] < INFINITY;
  105.          m = MARK_AT_LINE(lnum[i - 1] + 1))
  106.     {
  107.         /* fetch the block */
  108.         blk = blkget(i);
  109.  
  110.         /* find the mark in the block */
  111.         scan = blk->c;
  112.         for (l = markline(m) - lnum[i - 1] - 1; l > 0; l--)
  113.         {
  114.             while (*scan++ != '\n')
  115.             {
  116.             }
  117.         }
  118.         scan += markidx(m);
  119.  
  120.         /* figure out where the changes to this block end */
  121.         if (markline(tomark) > lnum[i])
  122.         {
  123.             cpy = blk->c + BLKSIZE;
  124.         }
  125.         else if (markline(tomark) == markline(m))
  126.         {
  127.             cpy = scan - markidx(m) + markidx(tomark);
  128.         }
  129.         else
  130.         {
  131.             cpy = scan;
  132.             for (l = markline(tomark) - markline(m);
  133.                  l > 0;
  134.                  l--)
  135.             {
  136.                 while (*cpy++ != '\n')
  137.                 {
  138.                 }
  139.             }
  140.             cpy += markidx(tomark);
  141.         }
  142.  
  143.         /* delete the stuff by moving chars within this block */
  144.         while (cpy < blk->c + BLKSIZE)
  145.         {
  146.             *scan++ = *cpy++;
  147.         }
  148.         while (scan < blk->c + BLKSIZE)
  149.         {
  150.             *scan++ = '\0';
  151.         }
  152.  
  153.         /* adjust tomark to allow for lines deleted from this block */
  154.         tomark -= MARK_AT_LINE(lnum[i] + 1 - markline(m));
  155.  
  156.         /* if this block isn't empty now, then advance i */
  157.         if (*blk->c)
  158.         {
  159.             i++;
  160.         }
  161.  
  162.         /* the buffer has changed.  Update hdr and lnum. */
  163.         blkdirty(blk);
  164.     }
  165.  
  166.     /* must have at least 1 line */
  167.     if (nlines == 0)
  168.     {
  169.         blk = blkadd(1);
  170.         blk->c[0] = '\n';
  171.         blkdirty(blk);
  172.         cursor = MARK_FIRST;
  173.     }
  174. }
  175.  
  176.  
  177. /* add some text at a specific place in the file */
  178. void add(atmark, newtext)
  179.     MARK        atmark;        /* where to insert the new text */
  180.     char        *newtext;    /* NUL-terminated string to insert */
  181. {
  182.     REG char    *scan;        /* used to move through string */
  183.     REG char    *build;        /* used while copying chars */
  184.     int        addlines;    /* number of lines we're adding */
  185.     int        lastpart;    /* size of last partial line */
  186.     BLK        *blk;        /* the block to be modified */
  187.     int        blkno;        /* the logical block# of (*blk) */
  188.     REG char    *newptr;    /* where new text starts in blk */
  189.     BLK        buf;        /* holds chars from orig blk */
  190.     BLK        linebuf;    /* holds part of line that didn't fit */
  191.     BLK        *following;    /* the BLK following the last BLK */
  192.     int        i;
  193.     long        l;
  194.  
  195. #ifdef DEBUG2
  196.     debout("add(%ld.%d, \"%s\")\n", markline(atmark), markidx(atmark), newtext);
  197. #endif
  198. #ifdef lint
  199.     buf.c[0] = 0;
  200. #endif
  201.     /* if not adding anything, return now */
  202.     if (!*newtext)
  203.     {
  204.         return;
  205.     }
  206.  
  207.     /* This is a change */
  208.     changes++;
  209.     significant = TRUE;
  210.  
  211.     /* count the number of lines in the new text */
  212.     for (scan = newtext, lastpart = addlines = 0; *scan; )
  213.     {
  214.         if (*scan++ == '\n')
  215.         {
  216.             addlines++;
  217.             lastpart = 0;
  218.         }
  219.         else
  220.         {
  221.             lastpart++;
  222.         }
  223.     }
  224.  
  225.     /* Reporting... */
  226.     if (lastpart == 0 && markidx(atmark) == 0)
  227.     {
  228.         rptlines = addlines;
  229.         rptlabel = "added";
  230.     }
  231.  
  232.     /* extract the line# from atmark */
  233.     l = markline(atmark);
  234.  
  235.     /* supply clues to the redraw module */
  236.     if ((markidx(atmark) == 0 && lastpart == 0) || addlines == 0)
  237.     {
  238.         redrawrange(l, l, l + addlines);
  239.     }
  240.     else
  241.     {
  242.         /* make sure the last line gets redrawn -- it was
  243.          * split, so its appearance has changed
  244.          */
  245.         redrawrange(l, l + 1L, l + addlines + 1L);
  246.     }
  247.  
  248.     /* adjust marks 'a through 'z and '' as needed */
  249.     for (i = 0; i < NMARKS; i++)
  250.     {
  251.         if (mark[i] < atmark)
  252.         {
  253.             /* earlier line, or earlier in same line: no change */
  254.             continue;
  255.         }
  256.         else if (markline(mark[i]) > l)
  257.         {
  258.             /* later line: move down a whole number of lines */
  259.             mark[i] += MARK_AT_LINE(addlines);
  260.         }
  261.         else
  262.         {
  263.             /* later in same line */
  264.             if (addlines > 0)
  265.             {
  266.                 /* multi-line add, which split this line:
  267.                  * move down, and possibly left or right,
  268.                  * depending on where the split was and how
  269.                  * much text was inserted after the last \n
  270.                  */
  271.                 mark[i] += MARK_AT_LINE(addlines) + lastpart - markidx(atmark);
  272.             }
  273.             else
  274.             {
  275.                 /* totally within this line: move right */
  276.                 mark[i] += lastpart;
  277.             }
  278.         }
  279.     }
  280.  
  281.     /* get the block to be modified */
  282.     for (blkno = 1; lnum[blkno] < l && lnum[blkno + 1] < INFINITY; blkno++)
  283.     {
  284.     }
  285.     blk = blkget(blkno);
  286.     buf = *blk;
  287.  
  288.     /* figure out where the new text starts */
  289.     for (newptr = buf.c, l = markline(atmark) - lnum[blkno - 1] - 1;
  290.          l > 0;
  291.          l--)
  292.     {
  293.         while (*newptr++ != '\n')
  294.         {
  295.         }
  296.     }
  297.     newptr += markidx(atmark);
  298.  
  299.     /* keep start of old block */
  300.     build = blk->c + (int)(newptr - buf.c);
  301.  
  302.     /* fill this block (or blocks) from the newtext string */
  303.     while (*newtext)
  304.     {
  305.         while (*newtext && build < blk->c + BLKSIZE - 1)
  306.         {
  307.             *build++ = *newtext++;
  308.         }
  309.         if (*newtext)
  310.         {
  311.             /* save the excess */
  312.             for (scan = linebuf.c + BLKSIZE;
  313.                  build > blk->c && build[-1] != '\n';
  314.                  )
  315.             {
  316.                 *--scan = *--build;
  317.             }
  318.  
  319.             /* write the block */
  320.             while (build < blk->c + BLKSIZE)
  321.             {
  322.                 *build++ = '\0';
  323.             }
  324.             blkdirty(blk);
  325.  
  326.             /* add another block */
  327.             blkno++;
  328.             blk = blkadd(blkno);
  329.  
  330.             /* copy in the excess from last time */
  331.             for (build = blk->c; scan < linebuf.c + BLKSIZE; )
  332.             {
  333.                 *build++ = *scan++;
  334.             }
  335.         }
  336.     }
  337.  
  338.     /* fill this block(s) from remainder of orig block */
  339.     while (newptr < buf.c + BLKSIZE && *newptr)
  340.     {
  341.         while (newptr < buf.c + BLKSIZE
  342.             && *newptr
  343.             && build < blk->c + BLKSIZE - 1)
  344.         {
  345.             *build++ = *newptr++;
  346.         }
  347.         if (newptr < buf.c + BLKSIZE && *newptr)
  348.         {
  349.             /* save the excess */
  350.             for (scan = linebuf.c + BLKSIZE;
  351.                  build > blk->c && build[-1] != '\n';
  352.                  )
  353.             {
  354.                 *--scan = *--build;
  355.             }
  356.  
  357.             /* write the block */
  358.             while (build < blk->c + BLKSIZE)
  359.             {
  360.                 *build++ = '\0';
  361.             }
  362.             blkdirty(blk);
  363.  
  364.             /* add another block */
  365.             blkno++;
  366.             blk = blkadd(blkno);
  367.  
  368.             /* copy in the excess from last time */
  369.             for (build = blk->c; scan < linebuf.c + BLKSIZE; )
  370.             {
  371.                 *build++ = *scan++;
  372.             }
  373.         }
  374.     }
  375.  
  376.     /* see if we can combine our last block with the following block */
  377.     if (lnum[blkno] < nlines && lnum[blkno + 1] - lnum[blkno] < (BLKSIZE >> 6))
  378.     {
  379.         /* hey, we probably can!  Get the following block & see... */
  380.         following = blkget(blkno + 1);
  381.         if (strlen(following->c) + (build - blk->c) < (unsigned)(BLKSIZE - 1))
  382.         {
  383.             /* we can!  Copy text from following to blk */
  384.             for (scan = following->c; *scan; )
  385.             {
  386.                 *build++ = *scan++;
  387.             }
  388.             while (build < blk->c + BLKSIZE)
  389.             {
  390.                 *build++ = '\0';
  391.             }
  392.             blkdirty(blk);
  393.  
  394.             /* pretend the following was the last blk */
  395.             blk = following;
  396.             build = blk->c;
  397.         }
  398.     }
  399.  
  400.     /* that last block is dirty by now */
  401.     while (build < blk->c + BLKSIZE)
  402.     {
  403.         *build++ = '\0';
  404.     }
  405.     blkdirty(blk);
  406. }
  407.  
  408.  
  409. /* change the text of a file */
  410. void change(frommark, tomark, newtext)
  411.     MARK    frommark, tomark;
  412.     char    *newtext;
  413. {
  414.     int    i;
  415.     long    l;
  416.     char    *text;
  417.     BLK    *blk;
  418.  
  419. #ifdef DEBUG2
  420.     debout("change(%ld.%d, %ld.%d, \"%s\")\n", markline(frommark), markidx(frommark), markline(tomark), markidx(tomark), newtext);
  421. #endif
  422.  
  423.     /* optimize for single-character replacement */
  424.     if (frommark + 1 == tomark && newtext[0] && !newtext[1] && newtext[0] != '\n')
  425.     {
  426.         /* find the block containing frommark */
  427.         l = markline(frommark);
  428.         for (i = 1; lnum[i] < l; i++)
  429.         {
  430.         }
  431.  
  432.         /* get the block */
  433.         blk = blkget(i);
  434.  
  435.         /* find the line within the block */
  436.         for (text = blk->c, i = l - lnum[i - 1] - 1; i > 0; text++)
  437.         {
  438.             if (*text == '\n')
  439.             {
  440.                 i--;
  441.             }
  442.         }
  443.  
  444.         /* replace the char */
  445.         text += markidx(frommark);
  446.         if (*text == newtext[0])
  447.         {
  448.             /* no change was needed - same char */
  449.             return;
  450.         }
  451.         else if (*text != '\n')
  452.         {
  453.             /* This is a change */
  454.             changes++;
  455.             significant = TRUE;
  456.             ChangeText
  457.             {
  458.                 *text = newtext[0];
  459.                 blkdirty(blk);
  460.             }
  461.             redrawrange(markline(frommark), markline(tomark), markline(frommark));
  462.             return;
  463.         }
  464.         /* else it is a complex change involving newline... */
  465.     }
  466.  
  467.     /* couldn't optimize, so do delete & add */
  468.     ChangeText
  469.     {
  470.         delete(frommark, tomark);
  471.         add(frommark, newtext);
  472.         rptlabel = "changed";
  473.     }
  474. }
  475.